<?php

namespace Biz\Services\App;

use Biz\Models\App\App;
use Lumen\Logger\Logger;
use Biz\Models\User\User;
use Biz\Models\App\AppSite;
use Illuminate\Http\Request;
use Biz\Libraries\LanguageUtil;
use Biz\Models\Passport\Client;
use Biz\Criteria\App\AppCriterion;
use Illuminate\Support\Facades\DB;
use Biz\Constants\App\AppConstants;
use Biz\Criteria\App\HasUserCriterion;
use Biz\Services\Passport\ClientService;
use Biz\Repositories\App\AppSiteRepository;
use Lumen\Core\Exceptions\BusinessException;
use Illuminate\Contracts\Pagination\Paginator;

/**
 * UserService.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class AppSiteService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * @var AppService
     */
    protected $appService;

    /**
     * @var ClientService
     */
    protected $clientService;

    /**
     * RepositoryController constructor.
     *
     * @param AppSiteRepository $repository
     * @param AppService        $appService
     * @param ClientService     $clientService
     */
    public function __construct(AppSiteRepository $repository, AppService $appService, ClientService $clientService)
    {
        $this->repository         = $repository;
        $this->appService         = $appService;
        $this->clientService      = $clientService;
    }

    /**
     * 列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function index(Request $request): Paginator
    {
        $user     = $request->user();
        $pageSize = $request->get('page_size', 10);

        $results = $this->repository
            ->pushCriterion(new HasUserCriterion($user))
            ->paginate($pageSize);

        return $results;
    }

    /**
     * Store.
     *
     * @param Request $request
     *
     * @throws \Exception
     *
     * @return AppSite
     */
    public function store(Request $request): AppSite
    {
        // Get Current User
        /** @var User $user */
        $user = $request->user();

        $data            = $request->all();
        $data['user_id'] = $user->id;

        return $this->create($data);
    }

    /**
     * Create.
     *
     * @param array $data
     *
     * @throws \Exception
     *
     * @return AppSite
     */
    public function create(array $data): AppSite
    {
        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 创建APP
            $data['type']  = AppConstants::TYPE_WEB_SITE;
            $app           = $this->appService->create($data);

            // 创建站点
            $data['app_id']             = $app->id;
            $allowField                 = $this->repository->createModel()->getFillable();
            $allowData                  = array_only($data, $allowField);
            /** @var AppSite $site */
            $site = $this->repository->create($allowData);
            if (! $site) {
                throw new BusinessException(trans('app.site_create_fail'));
            }
            $site->setApp($app);

            // 处理语言
            $languages = LanguageUtil::convertLanguagesData($data);
            $site->languages()->createMany($languages);
            $site->load('languages');

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $site;
    }

    /**
     * Find.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return AppSite
     */
    public function find(int $id): AppSite
    {
        $site = $this->repository->find($id);
        if (is_null($site)) {
            throw new BusinessException(trans('app.site_not_found'));
        }

        return $site;
    }

    /**
     * With find.
     *
     * @param int   $id
     * @param array $with
     *
     * @throws BusinessException
     *
     * @return AppSite
     */
    public function findWith(int $id, $with = []): AppSite
    {
        $site = $this->repository->with($with)->find($id);
        if (is_null($site)) {
            throw new BusinessException(trans('app.site_not_found'));
        }

        return $site;
    }

    /**
     * 获取详情.
     *
     * @param string $id
     *
     * @throws BusinessException
     *
     * @return AppSite
     */
    public function show(string $id): AppSite
    {
        $id   = AppSite::decodeUid($id);
        $this->repository->setCacheLifetime(0);
        $site = $this->findWith($id, ['app', 'app.client', 'languages']);

        return $site;
    }

    /**
     * 修改.
     *
     * @param string $id
     * @param array  $data
     *
     * @throws \Exception
     *
     * @return AppSite
     */
    public function edit(string $id, array $data): AppSite
    {
        $id   = AppSite::decodeUid($id);

        return $this->update($id, $data);
    }

    /**
     * 更新.
     *
     * @param int   $id
     * @param array $data
     *
     * @throws \Exception
     *
     * @return AppSite
     */
    public function update(int $id, array $data): AppSite
    {
        $site = $this->find($id);
        $app  = $this->appService->find($site->app_id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 更新OAuth客户端
            $data['redirect'] = $data['domain'];
            $this->clientService->update($app->client_id, $data);

            // 创建站点
            /** @var AppSite $site */
            $site = $this->repository->update($site, $data);
            if (! $site) {
                throw new BusinessException(trans('app.site_create_fail'));
            }

            // 处理语言
            $languages = LanguageUtil::convertLanguagesData($data);
            $site->languages()->delete();
            $site->languages()->createMany($languages);
            $site->load('languages');

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $site;
    }

    /**
     * 移除.
     *
     * @param string $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function remove(string $id): bool
    {
        $id   = AppSite::decodeUid($id);

        return $this->delete($id);
    }

    /**
     * 删除.
     *
     * @param int $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(int $id): bool
    {
        /** @var AppSite $site */
        $site = $this->find($id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $this->appService->delete($site->app_id);

            $this->repository->delete($id);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return true;
    }

    /**
     * Get Site By App.
     *
     * @param App $app
     *
     * @throws BusinessException
     *
     * @return AppSite
     */
    public function getSiteByApp(App $app): AppSite
    {
        $site = $this->repository
            ->pushCriterion(new AppCriterion($app))
            ->findFirst();
        if (is_null($site)) {
            throw new BusinessException(trans('app.site_not_found'));
        }

        return $site;
    }

    /**
     * Get Site By AppId And AppSecret.
     *
     * @param Client $oauthClient
     *
     * @throws BusinessException
     *
     * @return AppSite
     */
    public function getSiteByOAuthClient(Client $oauthClient): AppSite
    {
        $app = $this->appService->getAppByOAuthClient($oauthClient);

        $site = $this->getSiteByApp($app);

        return $site;
    }
}
